package com.sduept.nwld.mobile.manager.alarm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sduept.algorithm.wavelets.WaveletTree;
import com.sduept.algorithm.wavelets.spi.Daubechies;
import com.sduept.bigdata.fault.entity.BreakerActionInfo;
import com.sduept.bigdata.fault.entity.ProtectionActionInfo;
import com.sduept.bigdata.fault.model.CTSaturation;
import com.sduept.bigdata.fault.protection.model.ProtectChannelAlarm;
import com.sduept.bigdata.fault.protection.model.ProtectInterruptAlarm;
import com.sduept.cim.model.core.Substation;
import com.sduept.core.dao.SuperDAO;
import com.sduept.nwld.dataserver.manager.cim.CimManager;


@Service
public class AlarmQueryManager {
	@Resource
	private DataSource serverDatasource;
	@Autowired
	private CimManager cim;
	
	/**
	 * 通道一的情况
	 */
	private static List<String> list1 = Arrays.asList("通道一", "通道1", "通道A", "通道I", "A通道", "通道Ⅰ");
	/**
	 * 通道二的情况
	 */
	private static List<String> list2 = Arrays.asList("通道二", "通道2", "通道B", "通道II", "B通道", "通道Ⅱ");
	
	@Autowired
	private SuperDAO dao;
	
	/**
	 * 根据id获得CT饱和信息
	 * @param id
	 * @return
	 */
	public List<CTSaturation> getCTSaturationById(String id) {
		String sql = null;
		sql = " and id = ?";
		return getCTSaturationByCondition(sql, id);
	}
	public List<CTSaturation> getCTSaturationByCondition(String where, String id) {
		List<CTSaturation> list = new ArrayList<CTSaturation>();
		Connection conn = null;
		PreparedStatement pst = null;
		if (!StringUtils.isEmpty(where)) {
			where = " WHERE 1 = 1 " + where;
		} else {
			where = "";
		}
		String sql = "SELECT * FROM t_lbtz_saturation " + where;
		try {
			conn = serverDatasource.getConnection();
			pst = conn.prepareStatement(sql);
			if(null != id){
				pst.setString(1, id);
			}
			ResultSet rs = pst.executeQuery();
			while (rs.next()) {
				CTSaturation ct = getCTSaturation(rs);
				list.add(ct);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (pst != null)
					pst.close();
				if (conn != null)
					conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return list;
	}
	private CTSaturation getCTSaturation(ResultSet rs) throws SQLException {
		DecimalFormat df = new DecimalFormat("#.#####");
		CTSaturation ct = new CTSaturation();
		String faultFileId = rs.getString("fault_file_id");
		String stationId = rs.getString("station_id");
		String fault_line_name = rs.getString("fault_line_name");
		String fault_line_id = rs.getString("fault_line_id");
		String faultTime = rs.getString("fault_time");
		String phase_type = rs.getString("phase_type");
		Double first_power_harmonic = rs.getDouble("first_power_harmonic");
		Double second_power_harmonic = rs.getDouble("second_power_harmonic");
		Double third_power_harmonic = rs.getDouble("third_power_harmonic");
		Double forth_power_harmonic = rs.getDouble("forth_power_harmonic");
		Double fifth_power_harmonic = rs.getDouble("fifth_power_harmonic");
		Double sixth_power_harmonic = rs.getDouble("sixth_power_harmonic");
		Double seventh_power_harmonic = rs.getDouble("seventh_power_harmonic");
		Double seventh_power_harmonic_proportion = rs.getDouble("seventh_power_harmonic_proportion");
		Double area_proportion = rs.getDouble("area_proportion");
		Double max_current = rs.getDouble("max_current");
		Double fault_current = rs.getDouble("fault_current");
		boolean isSatiate = rs.getBoolean("is_satiate");
		ct.setFaultFileId(faultFileId);
		ct.setStationId(stationId);
		ct.setLineId(fault_line_id);
		ct.setLineName(fault_line_name);
		ct.setFaultTime(faultTime);
		ct.setPhase(phase_type);
		ct.setFirstPowerHarmonic(df.format(first_power_harmonic) + "");
		ct.setSecondPowerHarmonic(df.format(second_power_harmonic) + "");
		ct.setThirdPowerHarmonic(df.format(third_power_harmonic) + "");
		ct.setForthPowerHarmonic(df.format(forth_power_harmonic) + "");
		ct.setFifthPowerHarmonic(df.format(fifth_power_harmonic) + "");
		ct.setSixthPowerHarmonic(df.format(sixth_power_harmonic) + "");
		ct.setSeventhPowerHarmonic(df.format(seventh_power_harmonic) + "");
		ct.setSeventhPowerHarmonicProportion(df.format(seventh_power_harmonic_proportion) + "");
		ct.setAreaProportion(df.format(area_proportion) + "");
		ct.setMaxCurrent(df.format(max_current) + "");
		ct.setFaultPointCurrent(df.format(fault_current) + "");
		ct.setSatiate(isSatiate);
		if (stationId != null) {
			Substation station=cim.getStationById(stationId);
			if(station!=null) {
				ct.setStationName(station.getName());
			}
		}
		return ct;
	}

	/**
	 * 根据保护装置Id和日期查询保护装置中断告警
	 * 
	 * @param protectId
	 * @param sdate
	 * @param edate
	 * @return
	 */
	public List<ProtectInterruptAlarm> getProtectInterruptAlarmByProtectIdAndDate(String protectId,Date sdate, Date edate) {
		List<ProtectInterruptAlarm> result = getProtectInterruptAlarmByCondition(null, protectId, sdate, edate, false);
		for (ProtectInterruptAlarm pa : result) {
			if (StringUtils.isEmpty(pa.getLineId()))
				continue;
			if (StringUtils.isEmpty(pa.getProtectType())) {
				continue;
			}
			List<ProtectChannelAlarm> casList = dao.findByCondition(
					"bhId=? AND (triggerTime>=? AND (recoveryTime<=? OR recoveryTime is null))",
					new Object[] { protectId, sdate, edate }, "ORDER BY recoveryTime DESC", null,
					ProtectChannelAlarm.class);
			ProtectChannelAlarm channelAlarms = checkProtectInterruptReason(pa, casList);
			if (channelAlarms != null) {
				pa.getChannelAlarms().add(channelAlarms);
			}
		}
		return result;
	}
	/**
	 * 检测保护通道中断是否是通道引起的
	 * 
	 * @param alarm
	 * @return 如果是通道引起的返回通道信息，不是通道引起的返回null
	 */
	public ProtectChannelAlarm checkProtectInterruptReason(ProtectInterruptAlarm alarm,
			List<ProtectChannelAlarm> channelList) {
		long start = alarm.getEventStart().getTime() + alarm.getmStartMs();
		long end = start + alarm.getDurationTime();
		for (ProtectChannelAlarm calarm : channelList) {
			if (calarm.getTriggerTime() != null && calarm.getTriggerTime().getTime() <= start
					&& (calarm.getRecoveryTime() == null || calarm.getRecoveryTime().getTime() >= end)
					&& (calarm.getBhId() != null && calarm.getBhId().equals(alarm.getProtectId()))) {
				boolean flag1 = false;
				boolean flag2 = false;
				String channel = calarm.getAlarmChannel();
				for (String str : list1) {
					if (alarm.getAlarmMsg().contains(str)) {
						flag1 = true;
					}
					if (channel.contains(str)) {
						flag2 = true;
					}
				}
				if (flag1 && flag2)
					return calarm;

				flag1 = false;
				flag2 = false;
				for (String str : list2) {
					if (alarm.getAlarmMsg().contains(str)) {
						flag1 = true;
					}
					if (channel.contains(str)) {
						flag2 = true;
					}
				}
				if (flag1 && flag2)
					return calarm;
			}
		}
		return null;
	}
	/**
	 * 根据条件进行查询
	 * @param stationId
	 * @param protectId
	 * @param sdate
	 * @param edate
	 * @return
	 */
	private List<ProtectInterruptAlarm> getProtectInterruptAlarmByCondition(String stationId,String protectId,Date sdate, Date edate,boolean isUseRevertFilter){
		StringBuilder sb = new StringBuilder("1=1 ");
		List<Object> paramsList = new ArrayList<Object>();
		if(StringUtils.isNotEmpty(stationId)){
			sb.append(" AND stationId = ?");
			paramsList.add(stationId);
		}
		if(StringUtils.isNotEmpty(protectId)){
			sb.append(" AND protectId = ?");
			paramsList.add(protectId);
		}
		if(sdate!=null){
			sb.append(" AND eventStart >= ?");
			paramsList.add(sdate);
		}
		if(edate!=null){
			sb.append(" AND eventStart <= ?");
			paramsList.add(edate);
		}
		if(isUseRevertFilter){
			sb.append(" AND revertTime is null");
		}
		return dao.findByCondition(sb.toString(),paramsList.toArray(), "order by eventStart,mStartMs", null,ProtectInterruptAlarm.class);
	}
	/**
	 * 根据id获得保护动作时间
	 * @param id
	 * @return
	 */
	public ProtectionActionInfo getProtectionActionInfoById(String id){
		if(StringUtils.isNotEmpty(id)) {
			return dao.findById(id, ProtectionActionInfo.class);
		}
		return null;
	}
	/**
	 * 根据id获得断路器动作时间
	 * @param id
	 * @return
	 */
	public BreakerActionInfo getBreakerActionInfoById(String id){
		if(StringUtils.isNotEmpty(id)) {
			return dao.findById(id, BreakerActionInfo.class);
		}
		return null;
	}
	/**
	 * 获得指定故障文件中的指定断路器的故障后波形原始数据,小波分解后的数据
	 * @param breaker_id
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public double[][] getPostFaultWaveletData(String faultFileId,String breakerID,String phase){
//		List<?> objs = dao.nativeQuery("select post_fault_wave_data from t_lbtz_breaker_wave_data where"
//				+ " fault_file_id='"+faultFileId+"' and breaker_id='"+breakerID+"'");
		String sql = "select post_fault_wave_data from t_lbtz_breaker_wave_data where"
				+ " fault_file_id = ? and breaker_id = ?";
		Object[] whereArgs = new Object[2];
		whereArgs[0] = faultFileId;
		whereArgs[1] = breakerID;
		List<?> objs = dao.nativeQuery(sql, whereArgs);//改为防sql注入
		double[][] rtn = null;
		if(objs != null & objs.size() == 1){
			Object pwds = objs.get(0);
			double[] source;
			try {
				source = getWaveD(pwds.toString(),phase);
				if(source != null && source.length > 0){
					WaveletTree wp = Daubechies.db10.translate(source,3); 
					double[] r10 = wp.reconstruct(1, 0);
					double[] r11 = wp.reconstruct(1, 1);
					double[] r20 = wp.reconstruct(2, 0);
					double[] r21 = wp.reconstruct(2, 1);
					double[] r22 = wp.reconstruct(2, 2);
					double[] r23 = wp.reconstruct(2, 3);
					
					
					double[] r2122 = new double[r21.length];
					for (int i = 0; i < r2122.length; i++) {
						r2122[i] = r21[i]+r22[i];
					}
					double[] r30 = wp.reconstruct(3, 0);
					double[] r31 = wp.reconstruct(3, 1);
					double[] r32 = wp.reconstruct(3, 2);
					double[] r33 = wp.reconstruct(3, 3);
					rtn = new double[][]{source,r10,r11,r20,r21,r22,r2122,r23,r30,r31,r32,r33};
					//rtn = new double[][]{source,r10,r11,r20,r21,r22,r2122,r23};
				}
			} catch (NumberFormatException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return rtn;
	}
	/**
	 * 获得指定故障文件中的指定断路器的故障前波形原始数据,小波分解后的数据
	 * @param breaker_id
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public double[][] getPreFaultWaveletData(String faultFileId,String breakerID,String phase){
//		List<?> objs = dao.nativeQuery("select pre_fault_wave_data from t_lbtz_breaker_wave_data where"
//				+ " fault_file_id='"+faultFileId+"' and breaker_id='"+breakerID+"'");
		String sql = "select pre_fault_wave_data from t_lbtz_breaker_wave_data where"
			+ " fault_file_id = ? and breaker_id = ?";
		Object[] whereArgs = new Object[2];
		whereArgs[0] = faultFileId;
		whereArgs[1] = breakerID;
		List<?> objs = dao.nativeQuery(sql, whereArgs);//改为防sql注入
		double[][] rtn = null;
		if(objs != null & objs.size() == 1){
			Object pwds = objs.get(0);
			double[] source;
			try {
				source = getWaveD(pwds.toString(),phase);
				if(source != null && source.length > 0){
					WaveletTree wp = Daubechies.db10.translate(source,3); 
					double[] r10 = wp.reconstruct(1, 0);
					double[] r11 = wp.reconstruct(1, 1);
					double[] r20 = wp.reconstruct(2, 0);
					double[] r21 = wp.reconstruct(2, 1);
					double[] r22 = wp.reconstruct(2, 2);
					double[] r23 = wp.reconstruct(2, 3);
					
					
					double[] r2122 = new double[r21.length];
					for (int i = 0; i < r2122.length; i++) {
						r2122[i] = r21[i]+r22[i];
					}
					double[] r30 = wp.reconstruct(3, 0);
					double[] r31 = wp.reconstruct(3, 1);
					double[] r32 = wp.reconstruct(3, 2);
					double[] r33 = wp.reconstruct(3, 3);
					rtn = new double[][]{source,r10,r11,r20,r21,r22,r2122,r23,r30,r31,r32,r33};
					//rtn = new double[][]{source,r10,r11,r20,r21,r22,r2122,r23};
				}
			} catch (NumberFormatException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return rtn;
	}
	private double[] getWaveD(String post_fault_wave_data,String phase) throws NumberFormatException, IOException{
		BufferedReader br = new BufferedReader(new StringReader(post_fault_wave_data));
		String valueString = null;
		List<Double> dbs = new ArrayList<>();
		int i = 2;
		if("A".equals(phase)){
			i = 2;
		}else if("B".equals(phase)){
			i = 3;
		}else if("C".equals(phase)){
			i = 4;
		}
		while ((valueString=br.readLine())!=null){
			String[] str = valueString.split(",");
			dbs.add(Double.parseDouble(str[i]));
		}
		double [] rtn = new double[dbs.size()];
		for (int j = 0; j < rtn.length; j++) {
			rtn[j] = dbs.get(j);
		}
		return rtn;
	}
}
